<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script id="VertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform float u_PointSize;
    void main(){
        gl_Position = a_Position;
        gl_PointSize = u_PointSize;
    }
</script>
<script id="RadianFragmentShader" type="x-shader/x-fragment">
    precision mediump float;


    float pi = radians(180.0);

    float getCosJ(){
        vec2 c = vec2(gl_PointCoord);
        vec2 mo = c - vec2(0.5,0.5);
        float l = mo.x;
        float x = distance(c,vec2(0.5,0.5));
        float cosj = l / x;
        return cosj;
    }

    bool getAngle(float j1,float j2,float t){
        float cosj = getCosJ() * t;
        float a = 0.0;
        float b = 0.0;
        if(t > 0.0){
            if(j1 < j2){
                a = cos(min(j1, 180.0) * pi / 180.0);
                b = cos(min(j2, 180.0) * pi / 180.0);
                if(a >= cosj && cosj >= b){
                    return true;
                }
            }else{
                //逆开角(先不算)
                a = cos(min(j2, 180.0) * pi / 180.0);
                b = cos(min(j1, 180.0) * pi / 180.0);
                if(!(a >= cosj && cosj >= b)){
                    return true;
                }
            }
        }else{
            //负角
            if(j1 < j2){
                a = cos(max(j1 - 180.0, 0.0) * pi / 180.0);
                b = cos(max(min(j2 - 180.0, 180.0), 0.0) * pi / 180.0);
                if(a >= cosj && cosj >= b){
                    return true;
                }
            }else{
                //逆开角(先不算)
                a = cos(max(j2 - 180.0, 0.0) * pi / 180.0);
                b = cos(max(min(j1 - 180.0, 180.0), 0.0) * pi / 180.0);
                if(!(a >= cosj && cosj >= b)){
                    return true;
                }
            }
        }

        return false;
    }

    //获取弧线头部的圆心到圆心的距离
    // j:从[0.5,0.5]的角度 posiRadius:弧线半径 radius:画的圆的半径 diffRadius:扩散半径
    float getAngular(float j, float posiRadius){
        float x = posiRadius;
        float l = x * cos(j * pi / 180.0);
        float d = x * sin((360.0 - j) * pi / 180.0);

        vec2 c = vec2(l + 0.5, d + 0.5);
        float dist = distance(gl_PointCoord, c);
        return dist;
    }

    //画弧线
    bool drawAngle(
        float j1, float j2,
        float lineStart, float lineEnd,
        float lineDiff,
        vec4 color
    ){
        bool s = false;
        if(gl_PointCoord.y <= 0.5){
            s = getAngle(j1, j2, 1.0);
        }else{
            s = getAngle(j1, j2,-1.0);
        }
        if(s == true){
            float dist = distance(gl_PointCoord, vec2(0.5,0.5));
            if(dist <= lineStart && dist >= lineEnd){
                
                if(dist >= lineStart - lineDiff){
                    //外渐变
                    color.a *= 1.0 - (dist - (lineStart - lineDiff)) / (lineDiff);
                    gl_FragColor = color;
                    return false;
                }else if(dist <= lineEnd + lineDiff){
                    //内渐变
                    color.a *= (dist - lineEnd) / (lineDiff);
                    gl_FragColor = color;
                    return false;
                }else{
                    //实线
                    gl_FragColor = color;
                    return false;
                }
            }
        }
        return true;
    }

    bool drawAngular(
        float j1, float j2,
        float lineStart, float lineRadius, float lineDiff,
        vec4 color
    ){
        float dist = getAngular(j1, lineStart - lineRadius - lineDiff);
        if(dist < lineRadius + lineDiff){
            color.a *= 1.0 - (dist - lineRadius) / (lineDiff);
            gl_FragColor = color;
            return false;
        }

        dist = getAngular(j2, lineStart - lineRadius - lineDiff);
        if(dist < lineRadius + lineDiff){
            color.a *= 1.0 - (dist - lineRadius) / (lineDiff);
            gl_FragColor = color;
            return false;
        }
        return true;
    }

    float getJ2(float j1, float j2, float set){
        float offAngle = 0.5;
        float curJ2 = j2;
        if(set <= offAngle){
            if(j1 > curJ2){
                curJ2 += 360.0;
            }
            curJ2 = (curJ2 - j1) * (set / offAngle) + j1;
            if(curJ2 > 360.0){
                curJ2 -= 360.0;
            }
        }else{
            curJ2 = j2;
        }
        return curJ2;
    }

    float getJ1(float j1, float j2, float set){
        float offAngle = 0.5;
        if(set >= offAngle){
            float xnj2 = j2;
            if(xnj2 < j1){
                xnj2 += 360.0;
            }
            j1 = (xnj2 - j1) * ((set - offAngle) / (1.0 - offAngle)) + j1;

            if(j1 > 360.0){
                j1 -= 360.0;
            }
        }
        return j1;
    }

    //float line_W_S = 0.5;
    //float line_W_Dia = 0.00;//直径
    //float line_W_Diff = 0.05;//扩散半径
    //float line_W_E = line_W_S - line_W_Dia - line_W_Diff * 2.0;
    //vec4 u_line_W_Color = vec4(1,1,1,1);
    //float u_j1 = 0.0;
    //float u_j2 = 180.0;

    uniform float u_line_S;
    uniform float u_line_Dia;//直径
    uniform float u_line_Diff;//扩散半径
    uniform vec4 u_line_Color;

    uniform float u_Set;
    uniform float u_j1;
    uniform float u_j2;

    
    

    void main(){
        float u_line_E = u_line_S - u_line_Dia - u_line_Diff * 2.0;
 
        if(u_Set >= 1.0){
            return;
        }

        float j1 = u_j1;
        //计算角二
        float j2 = getJ2(j1, u_j2, u_Set);

        j1 = getJ1(j1, j2, u_Set);

        j1 += u_Set * 100.0;
        j2 += u_Set * 100.0;
        if(j1 >= 360.0){
            j1 -= 360.0;
        }
        if(j2 >= 360.0){
            j2 -= 360.0;
        }
            

        //计算弧线
        if(drawAngle(j1, j2, u_line_S, u_line_E, u_line_Diff, u_line_Color) == true){
            //计算圆角
            drawAngular(j1, j2, u_line_S, u_line_Dia / 2.0, u_line_Diff, u_line_Color);
        }

        
        
    }
</script>
<script type="module">


    import { Matrix4, Vector3, Color, OrthographicCamera, PerspectiveCamera, Spherical } from '../js/three.module.js';
    import { CreateProgram, imgPromise } from '../js/Utils.js';
    import lib from '../js/ThreeLib.js';
    import CameraController from '../js/CameraController.js'
    import Poly from '../js/Poly4.js'
    import Control from '../js/Control.js'
    import AngleDraw from '../js/AngleDraw.js'


    import Geo from '../js/Poly2/Geo.js'
    import Mat from '../js/Poly2/Mat.js'
    import Obj3D from '../js/Poly2/Obj3D.js'
    import Scene from '../js/Poly2/Scene.js'




    //#region gl
    const canvas = document.getElementById("canvas");
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight - 4;

    const gl = canvas.getContext("webgl", { antialias: true, });

    // gl.enable(gl.DEPTH_TEST);//开始背景遮挡会频闪
    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);//去图片描边
    //#endregion



    const scene = new Scene({ gl: gl });
    scene.regProgram('radian', {
        program: CreateProgram(gl,
            document.querySelector('#VertexShader').innerText,
            document.querySelector('#RadianFragmentShader').innerText),
        attribs: ['a_Position'],
        uniforms: [
            'u_j1', 'u_j2', 'u_Set',
            'u_PointSize',
            'u_line_S', 'u_line_Dia', 'u_line_Diff', 'u_line_Color'
        ]
    })



    const config = {
        pointSize: 50,
        s: 0.01,


        whiteDiff: 0.03,//白色外扩
        lineDia: 0.0,
        blueDiff: 0.005,//蓝色外扩
        blueDia: 0.05 - 0.025,//蓝色直径

        // whiteDiff * 2 = blueDia + blueDiff * 2 = 完全覆盖
        // 总直径 = whiteDiff * 2 + lineDia
        // defConfig第二层参数 = 第一层参数 - 总直径 - 一般0.01重叠
    };

    const defConfig = (num) => {
        let statr = num;
        const { whiteDiff, lineDia, blueDiff, blueDia } = config;
        return [
            {
                //中心 = lineStart = statr - whiteDiff - lineDia / 2 + blueDiff + (blueDia / 2)
                lineStart: statr,
                lineDia: 0,
                lineDiff: whiteDiff,
                lineColor: [1, 1, 1, 1],
            }, {
                lineStart: statr - whiteDiff - lineDia / 2 + blueDiff + (blueDia / 2),
                lineDia: blueDia,
                lineDiff: blueDiff,
                lineColor: [0, 1, 1, 1],
            }
        ];
    };


    const dataArr = [];



    scene.draw();

    canvas.addEventListener('pointerdown', function (event) {
        const { clientX, clientY } = event;

        const [x, y] = getViewPosi(clientX, clientY);

        //随机角度
        let angleStart = Math.random() * 360;
        let angleEnd = angleStart + Math.random() * 90 + 45;
        angleEnd = angleEnd > 360 ? angleEnd - 360 : angleEnd;
        createData(x, y, defConfig(0.5), [angleStart, angleEnd]);//第一层
        createData(x, y, defConfig(0.45), [angleEnd, angleStart]);//第二层

    });




    let kj = [0.0, 0.2];//开角动画
    (function ani() {

        for (let i = 0; i < dataArr.length; i++) {
            let { set, objs, pointSize } = dataArr[i];

            if (set > 1) {
                //删除
                deleteData(i);
                i--;
                continue;
            }

            dataArr[i].set += config.s;

            for (let j = 0; j < objs.length; j++) {
                objs[j].setUniform('u_Set', { value: dataArr[i].set });
                objs[j].setUniform('u_PointSize', { value: pointSize + (dataArr[i].set * pointSize) / 2 });
            }
        }



        scene.draw();
        requestAnimationFrame(ani);
    })();

    function deleteData(index) {
        let { objs } = dataArr[index];
        // console.log('删除了', objs.length, '个')
        for (let i = 0; i < objs.length; i++) {
            scene.remove(objs[i]);
        }
        // console.log('剩余', scene.children.length, '个')

        dataArr.splice(index, 1);
    }

    function createData(x, y, data, angle) {

        const curData = {
            set: 0,
            objs: [],
            pointSize: config.pointSize,
        };

        //创建弧度
        for (let i = 0; i < data.length; i++) {
            let cur = createRadian([x, y]);

            cur.setUniform('u_line_Color', { value: data[i].lineColor });
            cur.setUniform('u_PointSize', { value: curData.pointSize });
            cur.setUniform('u_j1', { value: angle[0] });
            cur.setUniform('u_j2', { value: angle[1] });
            cur.setUniform('u_line_S', { value: data[i].lineStart });
            cur.setUniform('u_line_Dia', { value: data[i].lineDia });
            cur.setUniform('u_line_Diff', { value: data[i].lineDiff });
            cur.setUniform('u_Set', { value: 0 });

            curData.objs.push(cur);
            scene.add(cur);
        }



        dataArr.push(curData);
    }

    function createRadian(node) {
        return new Obj3D({
            geo: new Geo({
                data: {
                    'a_Position': { size: 2, array: new Float32Array(node) },
                },
            }),
            mat: new Mat({
                program: 'radian',
                mode: ['POINTS'],
                data: {
                    'u_PointSize': { type: 'uniform1f', value: 0 },
                    'u_j1': { type: 'uniform1f', value: 0 },
                    'u_j2': { type: 'uniform1f', value: 0 },
                    'u_Set': { type: 'uniform1f', value: 0 },
                    'u_line_S': { type: 'uniform1f', value: 0 },
                    'u_line_Dia': { type: 'uniform1f', value: 0 },
                    'u_line_Diff': { type: 'uniform1f', value: 0 },
                    'u_line_Color': { type: 'uniform4fv', value: [0, 0, 0, 0] },
                },
            }),
        });
    }

    function getViewPosi(x, y) {
        const [hx, hy] = [canvas.width / 2, canvas.height / 2];
        const [cx, cy] = [
            (x - hx) / hx,
            -(y - hy) / hy,
        ];
        return [cx, cy];
    }

    function draw() {
        scene.draw();
    }
</script>
</script>

</html>